"""
AI自动开发 - 工具函数模块
提供通用工具函数、编码处理、错误处理等
"""

import os
import sys
import re
import ast
from pathlib import Path
from datetime import datetime
from typing import List, Dict, Any, Optional, Union
import functools


# ===== 编码修复 =====

def fix_encoding():
    """修复Windows环境下的编码问题"""
    # 设置环境变量
    os.environ['PYTHONIOENCODING'] = 'utf-8'

    # 如果可能，重设stdout和stderr编码
    try:
        import io
        if hasattr(sys.stdout, 'buffer'):
            sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
        if hasattr(sys.stderr, 'buffer'):
            sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
    except Exception:
        pass  # 如果失败就使用备用方案


# ===== 路径安全验证 =====

def is_safe_path(target_path: Union[str, Path], base_path: Union[str, Path]) -> bool:
    """
    检查目标路径是否在基础路径内（防止目录遍历攻击）

    参数:
    - target_path: 目标路径
    - base_path: 基础路径（安全边界）

    返回:
    - bool: 路径是否安全
    """
    try:
        target = Path(target_path).resolve()
        base = Path(base_path).resolve()
        return str(target).startswith(str(base))
    except Exception:
        return False


def normalize_path(path: Union[str, Path], base_path: Union[str, Path] = None) -> Path:
    """
    标准化路径，确保路径安全

    参数:
    - path: 要标准化的路径
    - base_path: 基础路径（可选）

    返回:
    - Path: 标准化后的路径对象
    """
    try:
        if base_path:
            base = Path(base_path).resolve()
            if not Path(path).is_absolute():
                # 相对路径，相对于base_path
                result = base / path
            else:
                result = Path(path).resolve()

            # 安全检查
            if not is_safe_path(result, base):
                raise ValueError(f"路径不安全: {path}")

            return result
        else:
            return Path(path).resolve()
    except Exception as e:
        raise ValueError(f"路径标准化失败: {str(e)}")


# ===== 文件操作工具 =====

def get_file_info(file_path: Union[str, Path]) -> Dict[str, Any]:
    """
    获取文件详细信息

    参数:
    - file_path: 文件路径

    返回:
    - dict: 文件信息字典
    """
    try:
        path = Path(file_path)
        if not path.exists():
            return {'exists': False}

        stat = path.stat()

        return {
            'exists': True,
            'is_file': path.is_file(),
            'is_dir': path.is_dir(),
            'size': stat.st_size,
            'created': datetime.fromtimestamp(stat.st_ctime).strftime('%Y-%m-%d %H:%M:%S'),
            'modified': datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
            'extension': path.suffix,
            'name': path.name,
            'parent': str(path.parent)
        }
    except Exception as e:
        return {'exists': False, 'error': str(e)}


def backup_file(file_path: Union[str, Path]) -> Optional[Path]:
    """
    备份文件，生成.bak文件

    参数:
    - file_path: 要备份的文件路径

    返回:
    - Path: 备份文件路径，失败返回None
    """
    try:
        source = Path(file_path)
        if not source.exists():
            return None

        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        backup_path = source.parent / f"{source.stem}_{timestamp}.bak"

        # 复制文件内容
        content = source.read_text(encoding='utf-8')
        backup_path.write_text(content, encoding='utf-8')

        return backup_path
    except Exception:
        return None


# ===== Python代码分析工具 =====

def extract_functions_from_code(code: str, file_path: str = "<string>") -> List[Dict[str, Any]]:
    """
    从Python代码中提取函数定义信息

    参数:
    - code: Python代码字符串
    - file_path: 文件路径（用于错误报告）

    返回:
    - list: 函数信息列表
    """
    functions = []

    try:
        tree = ast.parse(code)

        for node in ast.walk(tree):
            if isinstance(node, ast.FunctionDef):
                # 提取函数信息
                func_info = {
                    'name': node.name,
                    'line_start': node.lineno,
                    'line_end': getattr(node, 'end_lineno', node.lineno),
                    'args': [arg.arg for arg in node.args.args],
                    'docstring': ast.get_docstring(node),
                    'file_path': file_path
                }

                # 提取函数签名
                args_str = ', '.join(func_info['args'])
                func_info['signature'] = f"def {node.name}({args_str})"

                # 提取完整函数定义
                code_lines = code.split('\n')
                if func_info['line_end'] and func_info['line_end'] <= len(code_lines):
                    func_lines = code_lines[func_info['line_start'] - 1:func_info['line_end']]
                    func_info['full_definition'] = '\n'.join(func_lines)
                else:
                    # 如果end_lineno不可用，尝试估算
                    start_line = func_info['line_start'] - 1
                    func_lines = [code_lines[start_line]]
                    indent_level = len(code_lines[start_line]) - len(code_lines[start_line].lstrip())

                    for i in range(start_line + 1, len(code_lines)):
                        line = code_lines[i]
                        if line.strip() == '':
                            func_lines.append(line)
                        elif len(line) - len(line.lstrip()) > indent_level:
                            func_lines.append(line)
                        else:
                            break

                    func_info['full_definition'] = '\n'.join(func_lines)

                functions.append(func_info)

    except SyntaxError as e:
        # 代码有语法错误，返回错误信息
        return [{'error': f'语法错误: {str(e)}', 'file_path': file_path}]
    except Exception as e:
        return [{'error': f'分析错误: {str(e)}', 'file_path': file_path}]

    return functions


# ===== 内容搜索工具 =====

def search_in_text(text: str, query: str, context_lines: int = 2) -> List[Dict[str, Any]]:
    """
    在文本中搜索匹配内容

    参数:
    - text: 要搜索的文本
    - query: 搜索查询
    - context_lines: 上下文行数

    返回:
    - list: 搜索结果列表
    """
    results = []
    lines = text.split('\n')

    # 支持正则表达式搜索
    try:
        pattern = re.compile(query, re.IGNORECASE)
        use_regex = True
    except re.error:
        # 如果不是有效正则表达式，则使用普通字符串搜索
        use_regex = False

    for i, line in enumerate(lines):
        matched = False

        if use_regex:
            if pattern.search(line):
                matched = True
        else:
            if query.lower() in line.lower():
                matched = True

        if matched:
            # 提取上下文
            start_line = max(0, i - context_lines)
            end_line = min(len(lines), i + context_lines + 1)
            context = lines[start_line:end_line]

            results.append({
                'line_number': i + 1,
                'line_content': line,
                'context_lines': context,
                'context_start': start_line + 1,
                'context_end': end_line
            })

    return results


# ===== 错误处理装饰器 =====

def handle_errors(default_return=None, log_errors=True):
    """
    错误处理装饰器

    参数:
    - default_return: 出错时的默认返回值
    - log_errors: 是否记录错误
    """

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                if log_errors:
                    print(f"错误在 {func.__name__}: {str(e)}")
                return default_return

        return wrapper

    return decorator


# ===== 时间格式化工具 =====

def format_timestamp(timestamp_format: str = '%Y-%m-%d %H:%M:%S') -> str:
    """
    生成格式化的时间戳字符串

    参数:
    - timestamp_format: 时间格式字符串

    返回:
    - str: 格式化的时间戳
    """
    return datetime.now().strftime(timestamp_format)


def parse_timestamp(timestamp_str: str, timestamp_format: str = '%Y-%m-%d %H:%M:%S') -> Optional[datetime]:
    """
    解析时间戳字符串为datetime对象

    参数:
    - timestamp_str: 时间戳字符串
    - timestamp_format: 时间格式字符串

    返回:
    - datetime: 解析后的时间对象，失败返回None
    """
    try:
        return datetime.strptime(timestamp_str, timestamp_format)
    except ValueError:
        return None


# ===== 文件扩展名工具 =====

SUPPORTED_EXTENSIONS = {
    '.py': 'Python',
    '.js': 'JavaScript',
    '.ts': 'TypeScript',
    '.html': 'HTML',
    '.css': 'CSS',
    '.md': 'Markdown',
    '.txt': 'Text',
    '.json': 'JSON',
    '.yaml': 'YAML',
    '.yml': 'YAML',
    '.xml': 'XML',
    '.sql': 'SQL',
    '.log': 'LOG',
    '.java': 'Java',
    '.c': 'C',
    '.cpp': 'C++',
}


def get_file_type(file_path: Union[str, Path]) -> str:
    """
    根据文件扩展名获取文件类型

    参数:
    - file_path: 文件路径

    返回:
    - str: 文件类型名称
    """
    extension = Path(file_path).suffix.lower()
    return SUPPORTED_EXTENSIONS.get(extension, 'Unknown')


def is_text_file(file_path: Union[str, Path]) -> bool:
    """
    判断是否为文本文件

    参数:
    - file_path: 文件路径

    返回:
    - bool: 是否为文本文件
    """
    extension = Path(file_path).suffix.lower()
    return extension in SUPPORTED_EXTENSIONS


# ===== 字符串处理工具 =====

def truncate_string(text: str, max_length: int = 100, suffix: str = "...") -> str:
    """
    截断字符串到指定长度

    参数:
    - text: 要截断的字符串
    - max_length: 最大长度
    - suffix: 截断后缀

    返回:
    - str: 截断后的字符串
    """
    if len(text) <= max_length:
        return text
    return text[:max_length - len(suffix)] + suffix


def clean_whitespace(text: str) -> str:
    """
    清理多余的空白字符

    参数:
    - text: 要清理的文本

    返回:
    - str: 清理后的文本
    """
    # 移除首尾空白，将多个连续空白字符替换为单个空格
    return re.sub(r'\s+', ' ', text.strip())


# ===== 目录遍历工具 =====

def walk_directory(directory: Union[str, Path], max_depth: int = None, include_extensions: List[str] = None) -> List[
    Dict[str, Any]]:
    """
    遍历目录，返回文件信息列表

    参数:
    - directory: 要遍历的目录
    - max_depth: 最大深度限制
    - include_extensions: 包含的文件扩展名列表

    返回:
    - list: 文件信息列表
    """
    files = []
    directory = Path(directory)

    if not directory.exists() or not directory.is_dir():
        return files

    def _walk_recursive(current_dir: Path, current_depth: int = 0):
        if max_depth is not None and current_depth > max_depth:
            return

        try:
            for item in current_dir.iterdir():
                if item.is_file():
                    # 检查文件扩展名过滤
                    if include_extensions and item.suffix.lower() not in include_extensions:
                        continue

                    file_info = get_file_info(item)
                    file_info['relative_path'] = str(item.relative_to(directory))
                    file_info['depth'] = current_depth
                    files.append(file_info)

                elif item.is_dir():
                    # 递归遍历子目录
                    _walk_recursive(item, current_depth + 1)

        except PermissionError:
            # 跳过无权限访问的目录
            pass

    _walk_recursive(directory)
    return files


# 模块初始化
if __name__ == "__main__":
    # 应用编码修复
    fix_encoding()

    # 测试代码
    print("utils模块测试:")
    print(f"时间戳: {format_timestamp()}")
    print(f"支持的文件类型: {list(SUPPORTED_EXTENSIONS.keys())}")